#!/usr/bin/env python
# -*- coding:utf-8 -*- 
# Author: Jeokayne Ataier

#linux命令执行服务端
import struct
import subprocess
import socket
import json

server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR) 重复利用端口和IP的代码 --避免重启程序时的IP或端口占用冲突
server.bind(("127.0.0.1",8882))

server.listen(10)

while True:
    conn,addr = server.accept()

    while True:
        try:
            #1.接收头部信息长度
            header_len = struct.unpack("i",conn.recv(4))[0]

            #2.比较长度，接收头部信息
            recv_header_len = 0
            header = b""
            while recv_header_len < header_len:
                recv_header = conn.recv(1024)
                header += recv_header
                recv_header_len += len(recv_header)
            str_header = header.decode("utf-8")

            header_dic = json.loads(str_header)

            #3.获取数据长度后，正式开始接收信息
            data_size = header_dic["size"]
            recv_size = 0
            data = b""
            while recv_size < data_size:
                recv_data = conn.recv(1024)
                data += recv_data
                recv_size += len(recv_data)


            '''
            接收客户端信息结束，开始执行命令+传回数据
            '''
            output_obj=subprocess.Popen(data.decode("utf-8"),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
            stdout = output_obj.stdout.read() #执行命令未报错时，获得返回值（byte形式，传输无需encode） --os.system()执行后，返回0
            stderr = output_obj.stderr.read() #执行命令报错时，获得返回值（byte形式，传输无需encode） --os.system()执行后，返回非0
            '''
            客户端已经写好自动获取编码格式的代码，如果自己手动写decode，注意下面的编码：
            1.windows系统返回的byte需要用gbk解码decode
            2.Linux系统返回的byte需要用utf-8解码decode
            3.执行正确后，stderr返回值为空，反之亦然 --可优化
            '''
            if len(stdout+stderr) == 0:
                server_data = "返回值为空".encode("utf-8")
                print("返回值为空")
            else:
                server_data = stdout+stderr
                print("命令执行返回值为：",stdout+stderr)
                print("返回值长度为：",len(stdout+stderr))

            #1.构建可供传输的头部信息
            h1 = {
                "size":len(server_data)
            }
            h1_bytes = json.dumps(h1).encode("utf-8")

            #2.传输头部信息长度--打包为4个字节
            h1_len = struct.pack("i",len(h1_bytes))
            conn.send(h1_len)

            #3.传输头部信息
            conn.send(h1_bytes)

            #4.传输数据
            conn.send(server_data)
        except ConnectionResetError:
            break

    conn.close()